#ifndef Fifo_h_
#define Fifo_h_
#include "osplatform.h"
#include "Lock.h"
#include "Semaphore.h"

#if 1
#include <list>
template <class T>
class CFifo{
public:
	CFifo(){m_Sem.InitSemaphore(0,0);};
	virtual ~CFifo()
	{
		m_Lock.Lock();
		while(!m_Fifo.empty())
		{	 
			delete m_Fifo.front();
			m_Fifo.pop_front();
		}		
		m_Lock.Unlock();
	};	
	void Add(T *t);
	void AddAndSet(T *t);
	T* GetNext();
	T* PopFront();
	T* Front();
	uint32 Size();
	bool Available();
protected:
	typedef std::list<T*>	ItemContainer;
	ItemContainer			m_Fifo;
	CLock					m_Lock;
	CSemaphore				m_Sem;
};
template <class T>
void CFifo<T>::Add(T* t)
{
	/*if(t == NULL)
		return;
	m_Lock.Lock();
	m_Fifo.push_back(t);
	m_Lock.Unlock();*/
	AddAndSet(t);//yb 20100205, make sure GetNext is not blocked
}

template <class T>
void CFifo<T>::AddAndSet(T* t)
{
	//if(t == NULL)
	//	return;
	m_Lock.Lock();
	m_Fifo.push_back(t);
	if(m_Fifo.size() == 1) m_Sem.signal();
	m_Lock.Unlock();
}

template <class T>
T * CFifo<T>::GetNext()
{
	m_Lock.Lock();
	while(m_Fifo.empty())
	{
		m_Lock.Unlock();
		m_Sem.wait();
		m_Lock.Lock();
	}
	T *t = m_Fifo.front();
	m_Fifo.pop_front();
	m_Lock.Unlock();
	return t;
}

template <class T>
T * CFifo<T>::PopFront()
{
	T *t = NULL;
	m_Lock.Lock();
	if(m_Fifo.size() > 0)
	{
		t = m_Fifo.front();
		m_Fifo.pop_front();
	}
	m_Lock.Unlock();
	return t;
}

template <class T>
T * CFifo<T>::Front()
{
	T *t = NULL;
	m_Lock.Lock();
	if(m_Fifo.size() > 0)
	{
		t = m_Fifo.front();		
	}
	m_Lock.Unlock();
	return t;
}
template <class T>
uint32 CFifo<T>::Size() 
{	
	int size = 0;
	m_Lock.Lock();
	size = m_Fifo.size();
	m_Lock.Unlock();
	return size;
}

template <class T>
bool CFifo<T>::Available()
{	
	bool b;
	m_Lock.Lock();
	b = (!m_Fifo.empty());
	m_Lock.Unlock();
	return b;
}
/*
template <class T>
CFifo<T>::~CFifo()
{
//	CWaitAndSignal lock(m_Lock);
	while(!m_Fifo.empty())
	{	 
		delete m_Fifo.front();
		m_Fifo.pop_front();
	}
	m_nSize = 0;
}
*/
#else

#include "lffifo.h"
//typedef struct Myfifocell {
//	struct fifocell* volatile link;	/* next cell in the list */
//	void *pMyData;
//} Myfifocell;*/

template <class T>
class CFifo{
public:
	CFifo()
    {
     fifoinit(&m_Fifo);
     m_Sem.InitSemaphore(0,0);
     };
	virtual ~CFifo()
	{
	    fifocell *pMyfifocell = NULL;
		while(1)
		{	 
            pMyfifocell = fifoget(&m_Fifo);
            if(pMyfifocell == NULL)
                break;
            delete pMyfifocell;
		}		
		
	};	
	void Add(T *t);
	void AddAndSet(T *t);
	T* GetNext();
	T* PopFront();
	T* Front();
	uint32 Size();
	bool Available();
protected:
	
	fifo			m_Fifo;
	//CLock					m_Lock;
	CSemaphore				m_Sem;
};
template <class T>
void CFifo<T>::Add(T* t)
{
   if(t == NULL)return;
    fifocell *pMyfifocell = new fifocell;
    pMyfifocell->value[0] = (long)t;
    fifoput(&m_Fifo,(fifocell*)pMyfifocell);
}

template <class T>
void CFifo<T>::AddAndSet(T* t)
{
	if(t == NULL)
		return;
	
    fifocell *pMyfifocell = new fifocell;
    pMyfifocell->value[0] = (long)t;
    fifoput(&m_Fifo, pMyfifocell);
    if(Size() == 1)
        m_Sem.signal();
	
}

template <class T>
T * CFifo<T>::GetNext()
{
    T *t = NULL;
    fifocell *pMyfifocell = fifoget(&m_Fifo);
    
    while(pMyfifocell == NULL)
    {   
        m_Sem.wait();       
        pMyfifocell = fifoget(&m_Fifo);
     }

	 t = (T*)pMyfifocell->value[0];
    delete pMyfifocell;

	return t;
}

template <class T>
T * CFifo<T>::PopFront()
{
	T *t = NULL;
	fifocell *pMyfifocell = fifoget(&m_Fifo);
    if(pMyfifocell != 0)
	{
	    t = (T*)pMyfifocell->value[0];
        delete pMyfifocell;
    }
	return t;
}

template <class T>
T * CFifo<T>::Front()
{
	T *t = NULL;
	
	fifocell *pMyfifocell = fifoavail(&m_Fifo);
    if(pMyfifocell != 0)
	{
	    t = (T*)pMyfifocell->value[0];
    }
	return t;
}
template <class T>
uint32 CFifo<T>::Size() 
{	
	return fifosize(&m_Fifo);
}

template <class T>
bool CFifo<T>::Available()
{	
	fifocell *pMyfifocell = fifoavail(&m_Fifo);
    if(pMyfifocell != 0)
	{
	    return true;
    }
	return false;
}
/*
template <class T>
CFifo<T>::~CFifo()
{
//	CWaitAndSignal lock(m_Lock);
	while(!m_Fifo.empty())
	{	 
		delete m_Fifo.front();
		m_Fifo.pop_front();
	}
	m_nSize = 0;
}
*/

#endif
#endif
